package com.young.ums.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 验证码生成
 * @author wangjiyu@imdada.cn
 * @create 2018/12/14
 */
@Controller
public class SecurityCodeCreater {
    private static final Logger logger = LoggerFactory.getLogger(SecurityCodeCreater.class);
    private static int width = 120;// 定义图片的width
    private static int height = 30;// 定义图片的height
    private static int codeCount = 4;// 定义图片上显示验证码的个数
    private static int xx = 20;
    private static int fontHeight = 26;
    private static int codeY = 24;
    private static char[] codeSequence = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
                         'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    private static Map<Integer, int[][]> map = new HashMap<Integer, int[][]>(){
        {
            this.put(0, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2, 3, 4, 5, 6, 7, 8, 9}});
            this.put(1, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1}});
            this.put(2, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2}});
            this.put(3, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 3}});
            this.put(4, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2, 4}});
            this.put(5, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 5}});
            this.put(6, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2, 3, 6}});
            this.put(7, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 7}});
            this.put(8, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 2, 4, 8}});
            this.put(9, new int[][]{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {1, 3, 9}});
        }
    };
    private static String[] operatorArr = {"+", "-", "×", "÷"};

    /**
     * 生成验证码
     * @return
     */
    public static SecurityCodeImage createSecurityCodeImage() {
        SecurityCodeImage securityCode = new SecurityCodeImage();
        // 定义图像buffer
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // Graphics2D gd = buffImg.createGraphics();
        // Graphics2D gd = (Graphics2D) buffImg.getGraphics();
        Graphics gd = buffImg.getGraphics();
        // 创建一个随机数生成器类
        Random random = new Random();
        // 将图像填充为白色
        gd.setColor(Color.WHITE);
        gd.fillRect(0, 0, width, height);

        // 创建字体，字体的大小应该根据图片的高度来定。
        Font font = new Font("Fixedsys", Font.BOLD, fontHeight);
        // 设置字体。
        gd.setFont(font);

        // 画边框。
        gd.setColor(Color.BLACK);
        gd.drawRect(0, 0, width - 1, height - 1);

        // 随机产生40条干扰线，使图象中的认证码不易被其它程序探测到。
        gd.setColor(Color.BLACK);
        for (int i = 0; i < 30; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            gd.drawLine(x, y, x + xl, y + yl);
        }

        // randomCode用于保存随机产生的验证码
        StringBuffer randomCode = new StringBuffer();
        int red = 0, green = 0, blue = 0;

        //随机生成验证码字符串
        /*for (int i = 0; i < codeCount; i++) {
            randomCode.append(String.valueOf(codeSequence[random.nextInt(36)]));
        }
        securityCode.setCode(randomCode.toString());//设置验证码*/
        String[] codes = createMathSecurityCode();//生成数学计算形式的验证码
        randomCode.append(codes[0]);//0对应的值用来画验证码
        securityCode.setCode(codes[1]);//1对应的值是验证结果


        // 生成验证码图片
        for (int i = 0; i < randomCode.length(); i++) {
            // 验证码字符
            String code = String.valueOf(randomCode.charAt(i));

            // 产生随机的颜色分量来构造颜色值，这样输出的每位数字的颜色值都将不同。
            red = random.nextInt(255);
            green = random.nextInt(255);
            blue = random.nextInt(255);

            // 用随机产生的颜色将验证码绘制到图像中。
            gd.setColor(new Color(red, green, blue));
            gd.drawString(code, (i + 1) * xx, codeY);
        }

        securityCode.setImage(buffImg);
        securityCode.setCreateTime(new Date());
        return securityCode;
    }

    /**
     * 验证码包装类
     */
    public static class SecurityCodeImage {
        private String code;//验证码
        private BufferedImage image;//图片
        private Date createTime;//创建时间

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public BufferedImage getImage() {
            return image;
        }

        public void setImage(BufferedImage image) {
            this.image = image;
        }

        public Date getCreateTime() {
            return createTime;
        }

        public void setCreateTime(Date createTime) {
            this.createTime = createTime;
        }
    }

    @RequestMapping("/pic")
    public void pic(HttpServletResponse response){
        SecurityCodeImage securityCodeImage = createSecurityCodeImage();
        try {
            OutputStream os = response.getOutputStream();
            ImageIO.write(securityCodeImage.getImage(), "jpeg", os);
            os.close();
        } catch (IOException e) {
            logger.error("[下发验证码图片] 发生异常", e);
        }
    }
    /**
     * 从数组中随机取一个整数
     * @param arr
     * @return
     */
    static int getRandomIntFromArray(int[] arr){
        //arr.length以内的随机整数
        int radom = (int) (Math.random() * arr.length);
        return arr[radom];
    }

    /**
     * 返回小于指定值的随机正整数
     * @param num
     * @return
     */
    static int getRandomIntLessThen(int num){
        return (int) (Math.random() * num);
    }

    /**
     * 生成9以内加减乘除的验证码
     * @return 第一个值是验证码字符串,第二个值是计算结果
     */
    public static String[] createMathSecurityCode(){
        int numberA = getRandomIntLessThen(10);//数A
        int operatorIndex = getRandomIntLessThen(4);//运算符
        int[] numberBRange = map.get(numberA)[operatorIndex];//数B的取值范围
        int numberB = getRandomIntFromArray(numberBRange);//数B
        String code = new StringBuilder().append(numberA).append(operatorArr[operatorIndex]).append(numberB).append("=?").toString();
        int result = 0;
        switch (operatorIndex) {
            case 0:
                result = numberA + numberB;
                break;
            case 1:
                result = numberA - numberB;
                break;
            case 2:
                result = numberA * numberB;
                break;
            case 3:
                result = numberA / numberB;
                break;
            default:
                break;
        }
        return new String[]{code, String.valueOf(result)};
    }
}
